package org.xm.xmnlp.seg;

import org.xm.xmnlp.Xmnlp;
import org.xm.xmnlp.math.Dijkstra;
import org.xm.xmnlp.recognition.organ.OrganizationRecognition;
import org.xm.xmnlp.recognition.person.JapanesePersonRecognition;
import org.xm.xmnlp.recognition.person.PersonRecognition;
import org.xm.xmnlp.recognition.person.TranslatedPersonRecognition;
import org.xm.xmnlp.recognition.place.PlaceRecognition;
import org.xm.xmnlp.seg.domain.Graph;
import org.xm.xmnlp.seg.domain.Term;
import org.xm.xmnlp.seg.domain.Vertex;
import org.xm.xmnlp.seg.domain.WordNet;
import org.xm.xmnlp.seg.nshortpath.NShortPath;

import java.util.LinkedList;
import java.util.List;

/**
 * N最短分词器
 */
public class NShortSegment extends WordBasedModelSegment {
    List<Vertex> BiOptimumSegment(WordNet wordNetOptimum) {
        Graph graph = GenerateBiGraph(wordNetOptimum);
        if (Xmnlp.Config.DEBUG) {
            System.out.printf("细分词图：%s\n", graph.printByTo());
        }
        NShortPath nShortPath = new NShortPath(graph, 1);
        List<int[]> spResult = nShortPath.getNPaths(1);
        assert spResult.size() > 0 : "最短路径求解失败，请检查下图是否有悬孤节点或负圈\n" + graph.printByTo();
        return graph.parsePath(spResult.get(0));
    }

    @Override
    public List<Term> segSentence(char[] sentence) {
        WordNet wordNetOptimum = new WordNet(sentence);
        WordNet wordNetAll = new WordNet(sentence);
        //char[] charArray = text.toCharArray();
        // 粗分
        List<List<Vertex>> coarseResult = BiSegment(sentence, 2, wordNetOptimum, wordNetAll);
        boolean NERexists = false;
        for (List<Vertex> vertexList : coarseResult) {
            if (Xmnlp.Config.DEBUG) {
                System.out.println("粗分结果" + convert(vertexList, false));
            }
            // 实体命名识别
            if (tokenizerConfig.ner) {
                wordNetOptimum.addAll(vertexList);
                int preSize = wordNetOptimum.size();
                if (tokenizerConfig.nameRecognize) {
                    PersonRecognition.recognition(vertexList, wordNetOptimum, wordNetAll);
                }
                if (tokenizerConfig.translatedNameRecognize) {
                    TranslatedPersonRecognition.recognition(vertexList, wordNetOptimum, wordNetAll);
                }
                if (tokenizerConfig.japaneseNameRecognize) {
                    JapanesePersonRecognition.recognition(vertexList, wordNetOptimum, wordNetAll);
                }
                if (tokenizerConfig.placeRecognize) {
                    PlaceRecognition.recognition(vertexList, wordNetOptimum, wordNetAll);
                }
                if (tokenizerConfig.organizationRecognize) {
                    // 层叠隐马模型——生成输出作为下一级隐马输入
                    vertexList = Dijkstra.compute(GenerateBiGraph(wordNetOptimum));
                    wordNetOptimum.addAll(vertexList);
                    OrganizationRecognition.recognition(vertexList, wordNetOptimum, wordNetAll);
                }
                if (!NERexists && preSize != wordNetOptimum.size()) {
                    NERexists = true;
                }
            }
        }

        List<Vertex> vertexList = coarseResult.get(0);
        if (NERexists) {
            Graph graph = GenerateBiGraph(wordNetOptimum);
            vertexList = Dijkstra.compute(graph);
            if (Xmnlp.Config.DEBUG) {
                System.out.printf("细分词网：\n%s\n", wordNetOptimum);
                System.out.printf("细分词图：%s\n", graph.printByTo());
            }
        }

        // 数字识别
        if (tokenizerConfig.numberQuantifierRecognize) {
            mergeNumberQuantifier(vertexList, wordNetAll, tokenizerConfig);
        }

        // 如果是索引模式则全切分
        if (tokenizerConfig.indexMode) {
            return decorateResultForIndexMode(vertexList, wordNetAll);
        }

        // 是否标注词性
        if (tokenizerConfig.speechTagging) {
            speechTagging(vertexList);
        }

        if (tokenizerConfig.useCustomDictionary) {
            combineByCustomDictionary(vertexList);
        }

        return convert(vertexList, tokenizerConfig.offset);
    }

    /**
     * 二元语言模型分词
     *
     * @param sSentence      待分词的句子
     * @param nKind          需要几个结果
     * @param wordNetOptimum
     * @param wordNetAll
     * @return 一系列粗分结果
     */
    public List<List<Vertex>> BiSegment(char[] sSentence, int nKind, WordNet wordNetOptimum, WordNet wordNetAll) {
        List<List<Vertex>> coarseResult = new LinkedList<List<Vertex>>();
        //生成词网
        GenerateWordNet(wordNetAll);
        //logger.trace("词网大小：" + wordNetAll.size());
        //logger.trace("打印词网：\n" + wordNetAll);
        //生成词图
        Graph graph = GenerateBiGraph(wordNetAll);
        //logger.trace(graph.toString());
        if (Xmnlp.Config.DEBUG) {
            System.out.printf("打印词图：%s\n", graph.printByTo());
        }
        ///////////////N-最短路径////////////////////
        NShortPath nShortPath = new NShortPath(graph, nKind);
        List<int[]> spResult = nShortPath.getNPaths(nKind * 2);
        if (spResult.size() == 0) {
            throw new RuntimeException(nKind + "-最短路径求解失败，请检查上面的词网是否存在负圈或悬孤节点");
        }
        /*logger.trace(nKind + "-最短路径");
        for (int[] path : spResult)
        {
            logger.trace(Graph.parseResult(graph.parsePath(path)));
        }*/
        //日期、数字合并策略
        for (int[] path : spResult) {
            List<Vertex> vertexes = graph.parsePath(path);
            GenerateWord(vertexes, wordNetOptimum);
            coarseResult.add(vertexes);
        }
        return coarseResult;
    }

    /**
     * 一句话分词
     *
     * @param text
     * @return
     */
    public static List<Term> parse(String text) {
        return new NShortSegment().seg(text);
    }

    /**
     * 开启词性标注
     *
     * @param enable
     * @return
     */
    public NShortSegment enablePartOfSpeechTagging(boolean enable) {
        tokenizerConfig.speechTagging = enable;
        return this;
    }

    /**
     * 开启地名识别
     *
     * @param enable
     * @return
     */
    public NShortSegment enablePlaceRecognize(boolean enable) {
        tokenizerConfig.placeRecognize = enable;
        tokenizerConfig.updateNerConfig();
        return this;
    }

    /**
     * 开启机构名识别
     *
     * @param enable
     * @return
     */
    public NShortSegment enableOrganizationRecognize(boolean enable) {
        tokenizerConfig.organizationRecognize = enable;
        tokenizerConfig.updateNerConfig();
        return this;
    }

    /**
     * 是否启用音译人名识别
     *
     * @param enable
     */
    public NShortSegment enableTranslatedNameRecognize(boolean enable) {
        tokenizerConfig.translatedNameRecognize = enable;
        tokenizerConfig.updateNerConfig();
        return this;
    }

    /**
     * 是否启用日本人名识别
     *
     * @param enable
     */
    public NShortSegment enableJapaneseNameRecognize(boolean enable) {
        tokenizerConfig.japaneseNameRecognize = enable;
        tokenizerConfig.updateNerConfig();
        return this;
    }

    /**
     * 是否启用偏移量计算（开启后Term.offset才会被计算）
     *
     * @param enable
     * @return
     */
    public NShortSegment enableOffset(boolean enable) {
        tokenizerConfig.offset = enable;
        return this;
    }

    public NShortSegment enableAllNamedEntityRecognize(boolean enable) {
        tokenizerConfig.nameRecognize = enable;
        tokenizerConfig.japaneseNameRecognize = enable;
        tokenizerConfig.translatedNameRecognize = enable;
        tokenizerConfig.placeRecognize = enable;
        tokenizerConfig.organizationRecognize = enable;
        tokenizerConfig.updateNerConfig();
        return this;
    }

}
